//! Thin wrapper around `zen-expression` with ergonomic helpers plus custom-function utilities.
//! 使用 `zen-expression` 的表达式引擎，并额外提供自定义函数注册与上下文注入能力。

use serde::Serialize;
use serde_json::{Map, Value};
use std::sync::Arc;
use thiserror::Error;
use zen_expression::expression::{Standard, Unary};
pub use zen_expression::functions::arguments::Arguments;
use zen_expression::functions::mf_function::{MfFunctionHelper, MfFunctionRegistry};
pub use zen_expression::variable::VariableType;
use zen_expression::{
    Expression as InnerExpression, Isolate, IsolateError, Variable, compile_expression as compile_standard,
    compile_unary_expression as compile_unary, evaluate_expression as evaluate_standard, evaluate_unary_expression as evaluate_unary,
};

/// Result alias for all expression operations in this module.
/// 表达式相关 API 的统一返回类型。
pub type ExpressionResult<T> = Result<T, ExpressionError>;

/// Error type that merges serialization failures, engine errors and custom-function registration errors.
/// 错误类型，同时覆盖序列化、引擎执行以及自定义函数注册的错误。
#[derive(Debug, Error)]
pub enum ExpressionError {
    #[error("failed to serialize expression context: {0}")]
    Serialization(#[from] serde_json::Error),
    #[error(transparent)]
    Engine(#[from] IsolateError),
    #[error("expression result is not a boolean")]
    NonBoolean,
    #[error("custom function `{name}` registration failed: {reason}")]
    CustomFunction { name: String, reason: String },
}

/// Helper around `MfFunctionHelper` that keeps registration ergonomic for stateful custom functions.
/// 自定义函数注册辅助器，可针对某种 State 类型注册函数并在执行时获取 State。
pub struct CustomFunctionRegistry<S> {
    helper: MfFunctionHelper<S>,
}

impl<S: Send + Sync + 'static> CustomFunctionRegistry<S> {
    /// Create a new helper for the given state type.
    /// 创建一个新的辅助器实例。
    pub fn new() -> Self {
        Self { helper: MfFunctionHelper::new() }
    }

    /// Register a custom function that is able to read the optional state.
    /// 注册自定义函数，闭包可拿到 `Option<&S>` 获取执行时上下文。
    pub fn register_function<F, N>(
        &self,
        name: N,
        params: Vec<VariableType>,
        return_type: VariableType,
        executor: F,
    ) -> ExpressionResult<()>
    where
        F: Fn(&Arguments, Option<&S>) -> anyhow::Result<Variable> + 'static,
        N: Into<String>,
    {
        let owned = name.into();
        self.helper
            .register_function(owned.clone(), params, return_type, Box::new(executor))
            .map_err(|reason| ExpressionError::CustomFunction { name: owned.clone(), reason })
    }
}

impl<S: Send + Sync + 'static> Default for CustomFunctionRegistry<S> {
    fn default() -> Self {
        Self::new()
    }
}

/// Lists registered custom function names.
/// 列出当前注册的自定义函数名称。
pub fn list_custom_functions() -> Vec<String> {
    MfFunctionRegistry::list_functions()
}

/// Clears all registered custom functions.
/// 清理所有自定义函数（通常在测试结束时调用）。
pub fn clear_custom_functions() {
    MfFunctionRegistry::clear();
}

/// Evaluate an expression and return the raw [`Variable`].
/// 直接返回 `Variable`，便于自行处理类型。
pub fn eval_variable<T>(
    expression: &str,
    context: T,
) -> ExpressionResult<Variable>
where
    T: Serialize,
{
    let context = to_variable(context)?;
    let value = evaluate_standard(expression, context)?;
    Ok(value)
}

/// Evaluate an expression and convert the result to [`serde_json::Value`].
/// 返回 `serde_json::Value`，方便与现有 JSON 逻辑融合。
pub fn eval<T>(
    expression: &str,
    context: T,
) -> ExpressionResult<Value>
where
    T: Serialize,
{
    eval_variable(expression, context).map(Value::from)
}

/// Evaluate an expression that must yield a boolean.
/// 执行表达式并确保结果是布尔值，常用于条件判断。
pub fn eval_bool<T>(
    expression: &str,
    context: T,
) -> ExpressionResult<bool>
where
    T: Serialize,
{
    let result = eval_variable(expression, context)?;
    result.as_bool().ok_or(ExpressionError::NonBoolean)
}

/// Evaluate a unary expression where the current value is injected into `$`.
/// 用于类似 `filter($ > 10)` 的一元表达式。
pub fn eval_predicate<T>(
    expression: &str,
    current: T,
) -> ExpressionResult<bool>
where
    T: Serialize,
{
    let context = to_unary_variable(current)?;
    let value = evaluate_unary(expression, context)?;
    Ok(value)
}

/// Evaluate a standard expression while providing an execution state for custom functions.
/// 执行标准表达式并绑定一次性的 State，供自定义函数读取。
pub fn eval_with_state<T, S>(
    expression: &str,
    context: T,
    state: Arc<S>,
) -> ExpressionResult<Value>
where
    T: Serialize,
    S: Send + Sync + 'static,
{
    eval_variable_with_state(expression, context, state).map(Value::from)
}

/// Variant of [`eval_with_state`] that returns the raw [`Variable`].
/// 返回底层 `Variable`，供自定义解析。
pub fn eval_variable_with_state<T, S>(
    expression: &str,
    context: T,
    state: Arc<S>,
) -> ExpressionResult<Variable>
where
    T: Serialize,
    S: Send + Sync + 'static,
{
    let context = to_variable(context)?;
    let mut isolate = Isolate::with_environment(context);
    isolate.run_standard_with_state(expression, state).map_err(ExpressionError::from)
}

/// Evaluate a boolean expression with execution state.
/// 带 State 的布尔表达式求值封装。
pub fn eval_bool_with_state<T, S>(
    expression: &str,
    context: T,
    state: Arc<S>,
) -> ExpressionResult<bool>
where
    T: Serialize,
    S: Send + Sync + 'static,
{
    let result = eval_variable_with_state(expression, context, state)?;
    result.as_bool().ok_or(ExpressionError::NonBoolean)
}

/// Pre-compiled standard expression that can be re-used.
/// 预编译表达式，可在无状态场景反复使用。
pub struct CompiledExpression {
    inner: InnerExpression<Standard>,
}

impl CompiledExpression {
    /// Compile the provided expression source.
    pub fn new(source: &str) -> ExpressionResult<Self> {
        Ok(Self { inner: compile_standard(source)? })
    }

    /// Evaluate the compiled expression and return [`Variable`].
    pub fn evaluate_variable<T>(
        &self,
        context: T,
    ) -> ExpressionResult<Variable>
    where
        T: Serialize,
    {
        let context = to_variable(context)?;
        self.inner.evaluate(context).map_err(ExpressionError::from)
    }

    /// Evaluate and return [`serde_json::Value`].
    pub fn evaluate<T>(
        &self,
        context: T,
    ) -> ExpressionResult<Value>
    where
        T: Serialize,
    {
        self.evaluate_variable(context).map(Value::from)
    }

    /// Evaluate and ensure the result is boolean.
    pub fn evaluate_bool<T>(
        &self,
        context: T,
    ) -> ExpressionResult<bool>
    where
        T: Serialize,
    {
        let result = self.evaluate_variable(context)?;
        result.as_bool().ok_or(ExpressionError::NonBoolean)
    }
}

/// Pre-compiled unary expression (filter predicate).
pub struct CompiledPredicate {
    inner: InnerExpression<Unary>,
}

impl CompiledPredicate {
    /// Compile a unary expression (typically used inside `filter`/`some`).
    pub fn new(source: &str) -> ExpressionResult<Self> {
        Ok(Self { inner: compile_unary(source)? })
    }

    /// Evaluate the predicate against the provided current value.
    pub fn evaluate<T>(
        &self,
        current: T,
    ) -> ExpressionResult<bool>
    where
        T: Serialize,
    {
        let context = to_unary_variable(current)?;
        self.inner.evaluate(context).map_err(ExpressionError::from)
    }
}

fn to_variable<T>(input: T) -> ExpressionResult<Variable>
where
    T: Serialize,
{
    Ok(Variable::from(serde_json::to_value(input)?))
}

fn to_unary_variable<T>(input: T) -> ExpressionResult<Variable>
where
    T: Serialize,
{
    let mut map = Map::with_capacity(1);
    map.insert("$".into(), serde_json::to_value(input)?);
    Ok(Variable::from(Value::Object(map)))
}

#[cfg(test)]
mod tests {
    use super::*;
    use rust_decimal::Decimal;
    use serde_json::{Value, json};
    use std::collections::HashMap;
    use std::sync::{Arc, Mutex};

    #[derive(Debug)]
    struct CounterState {
        hits: Mutex<u32>,
    }

    impl CounterState {
        fn new() -> Self {
            Self { hits: Mutex::new(0) }
        }

        fn next(&self) -> u32 {
            let mut guard = self.hits.lock().unwrap();
            *guard += 1;
            *guard
        }
    }

    #[test]
    fn eval_supports_basic_math() {
        let result = eval("price * quantity", json!({ "price": 12, "quantity": 3 })).unwrap();
        assert_eq!(result, json!(36));
    }

    #[test]
    fn eval_variable_returns_raw_value() {
        let variable = eval_variable("payload", json!({ "payload": 42 })).unwrap();
        assert_eq!(Value::from(variable), json!(42));
    }

    #[test]
    fn bool_eval_enforces_type() {
        assert!(eval_bool("true", json!({})).unwrap());
        assert!(matches!(eval_bool("price", json!({ "price": 12 })), Err(ExpressionError::NonBoolean)));
    }

    #[test]
    fn predicate_helpers_wrap_dollar_context() {
        assert!(eval_predicate("> 5", 6).unwrap());
        assert!(!eval_predicate("in [10..20]", 5).unwrap());
    }

    #[test]
    fn eval_variable_with_state_exposes_variable() {
        clear_custom_functions();
        let registry = CustomFunctionRegistry::<CounterState>::new();
        registry
            .register_function("hit", vec![], VariableType::Number, |_, state| {
                let value = state.map(|s| s.next()).unwrap_or_default();
                Ok(Variable::Number(Decimal::from(value)))
            })
            .unwrap();

        let state = Arc::new(CounterState::new());
        let raw = eval_variable_with_state("hit()", json!({}), state).unwrap();
        assert_eq!(Value::from(raw), json!(1));

        clear_custom_functions();
    }

    #[test]
    fn eval_bool_with_state_checks_truthiness() {
        #[derive(Debug)]
        struct FlagState {
            enabled: bool,
        }

        clear_custom_functions();
        let registry = CustomFunctionRegistry::<FlagState>::new();
        registry
            .register_function("isEnabled", vec![], VariableType::Bool, |_, state| {
                let enabled = state.map(|s| s.enabled).unwrap_or(false);
                Ok(Variable::from(json!(enabled)))
            })
            .unwrap();

        assert!(eval_bool_with_state("isEnabled()", json!({}), Arc::new(FlagState { enabled: true })).unwrap());
        assert!(!eval_bool_with_state("isEnabled()", json!({}), Arc::new(FlagState { enabled: false })).unwrap());

        clear_custom_functions();
    }

    #[test]
    fn compiled_expression_reuses_bytecode() {
        let compiled = CompiledExpression::new("price * quantity + tax").unwrap();
        let first = compiled.evaluate(json!({ "price": 10, "quantity": 2, "tax": 5 })).unwrap();
        let second = compiled.evaluate(json!({ "price": 1, "quantity": 2, "tax": 3 })).unwrap();
        assert_eq!(first, json!(25));
        assert_eq!(second, json!(5));
    }

    #[test]
    fn compiled_predicate_handles_filters() {
        let predicate = CompiledPredicate::new("$ % 2 == 0").unwrap();
        assert!(predicate.evaluate(4).unwrap());
        assert!(!predicate.evaluate(5).unwrap());
    }

    #[test]
    fn custom_function_and_state_flow() {
        clear_custom_functions();
        let registry = CustomFunctionRegistry::<CounterState>::new();

        registry
            .register_function("nextHit", vec![], VariableType::Number, |_args, state| {
                let count = state.map(|s| s.next()).unwrap_or_default();
                Ok(Variable::Number(count.into()))
            })
            .unwrap();

        registry
            .register_function("whoAmI", vec![], VariableType::String, |_, state| {
                let id = state.map(|_| "ctx-bound".to_string()).unwrap_or_else(|| "missing".into());
                Ok(Variable::from(json!(id)))
            })
            .unwrap();

        let state = Arc::new(CounterState::new());

        let first = eval_with_state("nextHit()", json!({}), state.clone()).unwrap();
        assert_eq!(first, json!(1));
        let second = eval_with_state("nextHit()", json!({}), state.clone()).unwrap();
        assert_eq!(second, json!(2));
        let label = eval_with_state(r#"whoAmI()"#, json!({}), state.clone()).unwrap();
        assert_eq!(label, json!("ctx-bound"));

        let next = eval_with_state("nextHit()", json!({}), state).unwrap();
        assert_eq!(next, json!(3));

        clear_custom_functions();
    }

    #[test]
    fn custom_function_registry_lists_and_clears() {
        clear_custom_functions();
        let registry = CustomFunctionRegistry::<CounterState>::new();
        registry.register_function("f1", vec![], VariableType::Null, |_, _| Ok(Variable::Null)).unwrap();
        registry.register_function("f2", vec![], VariableType::Null, |_, _| Ok(Variable::Null)).unwrap();

        let functions = list_custom_functions();
        assert!(functions.contains(&"f1".to_string()));
        assert!(functions.contains(&"f2".to_string()));

        clear_custom_functions();
        assert!(list_custom_functions().is_empty());
    }

    #[derive(Debug)]
    struct TagState {
        tags: HashMap<String, String>,
    }

    impl TagState {
        fn new(entries: &[(&str, &str)]) -> Self {
            let tags = entries.iter().map(|(k, v)| (k.to_string(), v.to_string())).collect();
            Self { tags }
        }

        fn get(
            &self,
            key: &str,
        ) -> Option<&str> {
            self.tags.get(key).map(|v| v.as_str())
        }
    }

    #[test]
    fn custom_function_with_arguments() {
        clear_custom_functions();
        let registry = CustomFunctionRegistry::<TagState>::new();

        registry
            .register_function("tag", vec![VariableType::String], VariableType::String, |args, state| {
                let key = args.str(0)?;
                let value = state.and_then(|ctx| ctx.get(key)).map(|text| Variable::from(json!(text))).unwrap_or(Variable::Null);
                Ok(value)
            })
            .unwrap();

        let ctx = Arc::new(TagState::new(&[("user", "alice"), ("req", "R-1001")]));

        let user = eval_with_state(r#"tag("user")"#, json!({}), ctx.clone()).unwrap();
        assert_eq!(user, json!("alice"));

        let combined = eval_with_state(r#"tag("user") + "-" + tag("req")"#, json!({}), ctx.clone()).unwrap();
        assert_eq!(combined, json!("alice-R-1001"));

        let missing = eval_with_state(r#"tag("missing")"#, json!({}), ctx).unwrap();
        assert_eq!(missing, Value::Null);

        clear_custom_functions();
    }
}
